package studio.raptor.dispatcher.server.service;

import com.google.common.base.Strings;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import studio.raptor.dispatcher.common.constant.EventStatus;
import studio.raptor.dispatcher.server.entity.EventTrace;
import studio.raptor.hub.out.HubOut;
import studio.raptor.hubout.sdk.sender.Response;
import studio.raptor.hubout.sdk.sender.ResponseCode;

/**
 * 消息发送服务
 *
 * @author jack
 * @since 1.0
 */
@Service
public class SendService {

  private static final Logger log = LoggerFactory.getLogger(SendService.class);

  @Autowired
  HubOut hubOut;

  @Autowired
  CacheService cacheService;

  @Autowired
  GraphService graphService;

  @Autowired
  EventService eventService;


  /**
   * 异步发送消息
   */
  @Async
  public void sendMessage(String eventId, String code, Integer kindId, Integer eventType,
      boolean isSort) {
    Response response = null;
    try {
      String body = cacheService.fetchMessageBody(eventId, kindId, eventType);
      if (Strings.isNullOrEmpty(body)) {
        //todo 消息在缓存中不存在，重新抽取
      }
      response = hubOut.send(code, kindId, body);
      handleSendResponse(response, code, eventId, kindId, isSort);
      log.info("send message,code:[{}], eventId:[{}]", code, eventId);
    } catch (Exception e) {
      log.error("send message,code:[{}], eventId:[{}], failed:", code, eventId, e);
      response = Response.buildFailResp(ResponseCode.SEND_FAIL, e.getMessage());
      handleSendResponse(response, code, eventId, kindId, isSort);
    }

  }

  /**
   * 批量异步发送消息
   */
  @Async
  public void batchSendMessage(List<EventTrace> eventTraces, boolean isSort) {
    for (EventTrace eventTrace : eventTraces) {

      String eventId = eventTrace.getObjectKey();
      Integer kindId = eventTrace.getKindId();
      Integer eventType = eventTrace.getEventType();
      String code = eventTrace.getCode();
      if (eventTrace.getRetryTimes() > 10) {
        log.warn("Event[{}] a has been retry sent to:[{}] more than 10 times maximum", eventId,
            code);
      }
      Response response = null;
      try {
        String body = cacheService.fetchMessageBody(eventId, kindId, eventType);
        if (Strings.isNullOrEmpty(body)) {
          //todo 消息在缓存中不存在，重新抽取
        }
        response = hubOut.send(code, kindId, body);
        handleSendResponse(response, eventTrace, isSort);
        log.info("send message,code:[{}], eventId:[{}]", code, eventId);
      } catch (Exception e) {
        log.error("send message,code:[{}], eventId:[{}], failed:", code, eventId, e);
        response = Response.buildFailResp(ResponseCode.SEND_FAIL, e.getMessage());
        handleSendResponse(response, eventTrace, isSort);
      }
    }

  }

  private void handleSendResponse(Response response, String code, String eventId, Integer kindId,
      boolean isSort) {
    String status = response.isSuccess() ? EventStatus.SUCCESS : EventStatus.FAILED;
    if (isSort) {
      if (response.isSuccess()) {
        graphService.deleteEvent(eventId, code);
      } else {
        graphService.updateEventStatus(code, eventId, status);
      }
    }

    eventService.updateEventTrace(code, eventId, kindId, status, response.getCode(),
        response.getMsg());
  }


  private void handleSendResponse(Response response, EventTrace eventTrace, boolean isSort) {
    String status = response.isSuccess() ? EventStatus.SUCCESS : EventStatus.FAILED;
    String eventId = eventTrace.getObjectKey();
    String code = eventTrace.getCode();
    int retryTimes = eventTrace.getRetryTimes();
    if (isSort) {
      if (response.isSuccess()) {
        graphService.deleteEvent(eventId, code);
      } else {
        graphService.updateEventStatus(code, eventId, status);
      }
    }

    eventTrace.setStatus(status);
    eventTrace.setRespCode(response.getCode());
    eventTrace.setRespMsg(response.getMsg());
    eventTrace.setRetryTimes(++retryTimes);

    eventService.updateEventTrace(eventTrace);
  }

}
